home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BCI NET
/
BCI NET Dec 94.iso
/
archives
/
telecomm
/
bbs
/
axshsupp.lha
/
AXsh-Last.lha
/
usr
/
src
/
utils
/
last.c
Wrap
C/C++ Source or Header
|
1993-01-08
|
5KB
|
220 lines
/*
* Purpose
* -------
* Last-command for AXsh. Searches through a file containing
* info on user login times, and prints specific information. See
* last.man for further info.
*
* Technique
* ---------
* The applied technique is to search the file from start to
* end and store matching lines in a circular double-linked list.
* If the output limiter <-N> is used, no more memory than for N
* lines will be allocated, and the oldest ones will be recycled.
* In this way both disk access and memory usage is kept relatively
* low.
*
* Dynamic allocation is used for obtaining space for the lines,
* and if the program terminates normally, it frees the memory
* itself. If the user presses CTRL-C, the compiler's own routine
* handles the cleanup, including closing of files and deallocation
* of memory, even the dynamic allocated areas. I'm not sure if
* all compilers do this (correctly), but SAS/C 6.1 seems to handle
* it fine.
*
* The program only allocates 40 characters for each line, as the
* lines in the file are usually 37 or 38 characters long (including
* the carriage return). However this can be increased easily by
* changing the value of LINE_LEN.
*
* Syntax
* ------
* "last [-N] [login name]"
*
* <-N> limits output to N lines.
*
* <login name> is the login of the user to search for and
* defaults to anybody.
*
*
* History
* -------
* 02-Oct-92 Mads Haahr First version completed.
* 08-Jan-93 Mads Haahr Now supports varying line lengths (thanks
* Pasi), general program structure changed,
* most of the code rewritten.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#define LAST_FILE "AXsh:etc/Last" /* Name of the last file. */
#define LINE_LEN 40 /* Max length of a line minus one. */
/* Structures.
*/
struct line
{
char value[LINE_LEN];
struct line *next, *prev;
};
/* Prototypes.
*/
void store(char *s),
cleanup(void),
error(char *s, ...);
/* Global variables.
*/
FILE *fp;
int lines = 0, count = 0;
struct line *first = NULL, *last = NULL;
int main(int argc, char *argv[])
{
struct line *tmp;
char buf[LINE_LEN], match[LINE_LEN] = "\0";
int i;
switch(argc)
{
case 1 :
break;
case 2 :
if (argv[1][0] == '-')
{
lines = -atoi(argv[1]);
if (lines <= 0) error("Illegal number of lines", 0);
}
else
strncpy(match, argv[1], LINE_LEN-1);
break;
case 3 :
if (argv[1][0] == '-')
{
lines = -atoi(argv[1]);
if (lines <= 0) error("Illegal number of lines", 0);
}
else
error("Second argument is incorrect", 0);
strncpy(match, argv[2], LINE_LEN-1);
break;
default :
error("Too many arguments", 0);
}
/* Open the last file.
*/
if ((fp = fopen(LAST_FILE, "r")) == NULL) error("Could not open ", LAST_FILE, 0);
/* Here begins the actual
* reading & matching.
*/
while (fgets(buf, LINE_LEN, fp) != NULL)
if (strstr(buf, match))
store(buf);
/* Now we print out what we've found.
*/
for(tmp=last,i=count; i--; tmp=tmp->prev) printf("%s", tmp->value);
cleanup();
return(0);
}
void store(char *s)
{
struct line *tmp;
/* First check if no structures
* have been allocated yet.
*/
if (first == NULL)
{
/* Allocate memory for first
* structure and initialize it.
*/
if ((first = malloc(sizeof(struct line))) == NULL) error("Memory allocation failed", 0);
first->next = first;
first->prev = first;
last = first;
/* Store the string and set
* the line counter.
*/
strncpy(first->value, s, LINE_LEN);
count = 1;
return;
}
if (count < lines || lines == 0)
{
/* We haven't reached max the number of lines
* yet, so we allocate memory for one more.
*/
if ((tmp = malloc(sizeof(struct line))) == NULL)
error("Memory allocation failed", 0);
/* Link the new structure in
* and update the <last> pointer.
*/
tmp->prev = last;
last->next = tmp;
tmp->next = first;
first->prev = tmp;
last = tmp;
/* Store the string and increment
* the line counter.
*/
strncpy(tmp->value, s, LINE_LEN);
count++;
}
else
{
/* We have reached the max number of
* lines, so we recycle the oldest one.
*/
strncpy(first->value, s, LINE_LEN);
last = first;
first = first->next;
}
}
void cleanup(void)
{
struct line *tmp;
if (fp) fclose(fp);
for(tmp=first; count--; tmp=tmp->next) free(tmp);
}
void error(char *s, ...)
{
va_list ap;
printf("Last: ");
for(va_start(ap, s);s;s=va_arg(ap, char *)) printf("%s", s);
printf(".\n");
va_end(ap);
cleanup();
exit(10);
}